﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Collections.Generic;

namespace ProModel.ApplicationFramework.Silverlight
{
    public class CancelEventArgs : EventArgs
    {
        public bool Cancel { get; set; }

        public CancelEventArgs() { }
    }

    #region Definitions

    #region Enums

    /// <summary>Enumeration for specifying button usage in modal forms.</summary>
    public enum MsgBoxButtons
    {
        /// <summary>An OK button will appear on the form.</summary>
        OK,
        /// <summary>A Cancel OK button will appear on the form.</summary>
        Cancel,
        /// <summary>An OK button and a Cancel button will appear on the form.</summary>
        OKCancel,
        /// <summary>OK, Cancel and Apply button wills appear on the form.</summary>
        OKCancelApply
    }

    //public enum MsgBoxIcon
    //{
    //    Information,
    //    Warning,
    //    Error
    //}

    /// <summary>Enumeration for specifying a modal form's exit condition.</summary>
    public enum DialogExit
    {
        /// <summary>Indicates the user has cancelled the dialog operation.</summary>
        Cancel,
        /// <summary>Indicates the user has accepted the dialog operation.</summary>
        OK,
        /// <summary>Indicates the user wants to apply the dialog operation.</summary>
        Apply
    }

    internal enum RestoreState
    {
        Maximized,
        Unmaximized
    }

    #endregion

    #region Interfaces

    /// <summary>For internal use only.</summary>
    public interface IModal
    {
        /// <summary>For internal use only.</summary>
        UserControl HostedControl { get; set; }
    }

    #endregion

    #region Delegates

    /// <summary>Callback used to deliver the dialog result on close.</summary>
    public delegate bool DialogClose(object sender, DialogExit e);

    #endregion

    #endregion

    #region Modal Class

    /// <summary>
    /// The Modal class is used to show a UserControl modally with no surrounding window
    /// frame.
    /// </summary>
    /// <remarks>
    /// When using the modal class it should be noted that the consumer is responsible
    /// for handing window closure, etc.
    /// </remarks>
    public class Modal : IDisposable
    {
        public event EventHandler<CancelEventArgs> ModalClosing;
        public event EventHandler ModalClosed;

        #region Modal handlers

        protected IModal _modal;
        /// <summary>The PopupCreated is fired once the modal form has been displayed.</summary>
        public event EventHandler PopupCreated;

        protected internal Popup _popup = null;
        /// <summary>For internal use only.</summary>
        public Popup Popup
        {
            get { return _popup; }
            set { _popup = value; }
        }

        protected internal ModalHost _host;
        /// <summary>For internal use only.</summary>
        public ModalHost Host
        {
            get { return _host; }
            set { _host = value; }
        }

        private bool _isClosing;
        /// <summary>For internal use only.</summary>
        public bool IsClosing
        {
            get { return _isClosing; }
            set { _isClosing = value; }
        }

        protected virtual void ModalControl_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                HideModal();
            }
        }

        /// <summary>For internal use only.</summary>
        public virtual bool ShowModal(Panel root, IModal ctrl, bool useCanvasPainting)
        {
            _modal = ctrl;
            SetHost(ctrl, useCanvasPainting);
            WireEvents();
            return CreatePopup(root);
        }

        private bool CreatePopup(Panel root)
        {
            bool retSuccess = false;

            _popup = new Popup();
            FirePopupCreated();
            _popup.Child = _host;

            // recurse the window tree to find the highest level panel (should be the top-level LayoutRoot)  Ummm....???  Silverlight???  Thoughts on this one???
            Panel rootVisual = WindowHelpers.GetContainingPanel(root as FrameworkElement);
            if (rootVisual != null)
            {
                rootVisual.Children.Insert(0, _popup);
                _popup.IsOpen = true;
                retSuccess = true;
            }

            return retSuccess;
        }

        protected virtual void SetHost(IModal ctrl, bool useCanvasPainting)
        {
            _host = new ModalHost(ctrl, useCanvasPainting);
        }

        protected virtual void WireEvents()
        {
            UserControl control = _modal as UserControl;
            control.KeyUp += new KeyEventHandler(ModalControl_KeyUp);
        }

        protected virtual void UnwireEvents()
        {
            UserControl control = _modal as UserControl;
            control.KeyUp -= new KeyEventHandler(ModalControl_KeyUp);
        }

        protected void FirePopupCreated()
        {
            if (PopupCreated != null)
            {
                PopupCreated(this, EventArgs.Empty);
            }
        }

        /// <summary>For internal use only.</summary>
        public virtual UserControl HideModal()
        {
            if (ModalClosing != null)
            {
                CancelEventArgs e = new CancelEventArgs();
                ModalClosing(this, e);
                if (e.Cancel) return null;
            }

            Dispose();
            _isClosing = true;

            if (_popup != null)
            {
                _popup.IsOpen = false;
                _popup.Child = null;
                _popup = null;
            }

            if (_host != null)
            {
                UserControl retControl = _host.ChildControl;
                _host.Close();
                
                if (ModalClosed != null)
                    ModalClosed(this, EventArgs.Empty);

                return retControl;
            }
            else
            {
                if (ModalClosed != null)
                    ModalClosed(this, EventArgs.Empty);

                return null;
            }
        }
        #endregion

        #region IDisposable Members

        /// <summary>For internal use only.</summary>
        public virtual void Dispose()
        {
            UserControl uc = _modal as UserControl;
            IDisposable dispose = uc as IDisposable;

            if (dispose != null) dispose.Dispose();

            UnwireEvents();
        }

        #endregion
    }

    #endregion
}
